//
//  SWSeilal.m
//  SerialPort
//
//  Created by MT-SW-003 on 2021/4/9.
//  Copyright © 2021 MT-SW-003. All rights reserved.
//

#import "SWSeilal.h"

@implementation SWSeilal


/*
* get the number of opened serial device.
*
* @param fd The device number of serial device.
*
* @return fd The number of serial device.
*/
- (int)serialDevice:(int)fd {
    if (fd < 0) {
        NSLog(@"open device failed fd:%d",fd);
    }
    return fd;
}


/*
* Set serial port param
*
* @param fd Opened file number of the serial port device.
*
* @param baudRate Target baudRate of the serial port device.
*
* @param dataBit Target dataBit length of serial port device.
*
* @param Parity Target parity of the serial port device.
*
* @param stopBit Target stopBit of the serial port device.
*
* @return int The setting result.
*
*/
- (int)serialConfigForDevice:(int)fd
                withBaudRate:(int)baudRate
                 withDataBit:(int)dataBit
                 withStopBit:(int)stopBit
                  withParity:(char)parity {
    struct termios originConfig;
    struct termios targetConfig;
    
    // Read the original terminal configurations and check if failed
    if (tcgetattr(fd, &originConfig) != 0) {
      NSLog(@"Failed to read terminal description.");
      return (-1);
    }

    // Initialize cflag
    bzero(&targetConfig, sizeof(targetConfig)); //set the n bytes to 0 ,include‘\0’
    targetConfig.c_cflag |= CLOCAL | CREAD;

    // Set baud rate
    switch (baudRate) {
      // Baud rate 2400
      case 2400:
        cfsetispeed(&targetConfig, B2400);
        cfsetospeed(&targetConfig, B2400);
        break;

      // Baud rate 4800
      case 4800:
        cfsetispeed(&targetConfig, B4800);
        cfsetospeed(&targetConfig, B4800);
        break;

      // Baud rate 9600
      case 9600:
        cfsetispeed(&targetConfig, B9600);
        cfsetospeed(&targetConfig, B9600);
        break;

      // Baud rate 19200
      case 19200:
        cfsetispeed(&targetConfig, B19200);
        cfsetospeed(&targetConfig, B19200);
        break;

      // Baud rate 38400
      case 38400:
        cfsetispeed(&targetConfig, B38400);
        cfsetospeed(&targetConfig, B38400);
        break;

      // Baud rate 57600
      case 57600:
        cfsetispeed(&targetConfig, B57600);
        cfsetospeed(&targetConfig, B57600);
        break;

      // Baud rate 115200
      case 115200:
        cfsetispeed(&targetConfig, B115200);
        cfsetospeed(&targetConfig, B115200);
        break;
     //Baud rate 230400
     case 230400:
        cfsetispeed(&targetConfig, B230400);
        cfsetospeed(&targetConfig, B230400);
        break;
            
      // Invalid baud rate
      default:
        // Baud rate does not exist
        NSLog(@"Baud rate %d does not exist.", baudRate);
        return (-1);
    }

    // Set target data size
    targetConfig.c_cflag &= (~CSIZE);
    switch (dataBit) {
      // Data size 7
      case 7:
        targetConfig.c_cflag |= CS7;
        break;

      // Data size 8
      case 8:
        targetConfig.c_cflag |= CS8;
        break;

      // Invalid data size
      default:
        NSLog(@"dataBit %d does not exist.", dataBit);
        return (-1);
    }

    // Set target check parity
    switch (parity) {
      // None
      case'N':
        targetConfig.c_cflag &= (~PARENB);
        break;

      // Odd
      case'O':
        targetConfig.c_cflag |= PARENB;
        targetConfig.c_cflag |= PARODD;
        targetConfig.c_iflag |= (INPCK | ISTRIP);
        break;

      // Even
      case'E':
        targetConfig.c_cflag |= PARENB;
        targetConfig.c_cflag &= (~PARODD);
        targetConfig.c_iflag |= (INPCK | ISTRIP);
        break;

      // Invalid check parity
      default:
        NSLog(@"parity %c does not exist.", parity);
        return (-1);
    }

    // Set target stop bit
    switch (stopBit) {
      // 1 stop bit
      case 1:
        targetConfig.c_cflag &= (~CSTOPB);
        break;

      // 2 stop bits
      case 2:
        targetConfig.c_cflag |= CSTOPB;
        break;

      // Invalid stop bit
      default:
        NSLog(@"stopBit %d does not exist.", stopBit);
        return (-1);
    }

    // Set waiting time
    targetConfig.c_cc[VTIME] = 0;

    // Set minimum byte
    targetConfig.c_cc[VMIN] = 0;

    // Flush input and output queue
    tcflush(fd, TCIFLUSH);

    // Active the target configurations immediately and check the result
    if (tcsetattr(fd, TCSANOW, &targetConfig) != 0) {
        // "0" indicates success
      NSLog(@"Failed to configurate terminal description.");
      return -1;
    }

    // Return success
    return 1;
}
      
     
         
/*
* Write data to serial device
*
* @param fd The number of serial device.
*
* @return writeDataLength Length of write data.
*/
- (ssize_t)writeDataToDevice:(int)fd
                   writeBuff:(char *)sendData
             writeDataLength:(size_t)len {
    NSLog(@"write data:%s len:%zd to fd:%d",sendData,len,fd);
    ssize_t writeDataLength = write(fd,sendData,len);
    if (writeDataLength < 0) {
        NSLog(@"write failed:w_len:%zd\n",writeDataLength);
    }
    else {
        NSLog(@"writeData success\n");
    }
    return writeDataLength;
}


/*
* Read data from serial device
*
* @param fd The number of serial device.
*
* @return readDataDict Read data dict include read data length and read data str.
*/

/*
 ssize_t readData(int fd,char *readBuff,size_t r_len){
 ssize_t r_ok;
 r_ok= read(fd,readBuff,r_len);
 printf("r_ok %zd\n",r_ok);
 */
- (NSMutableDictionary *)readDataFromDevice:(int)fd
{
    char readBuff[1024];
    size_t len =1024;
    NSMutableDictionary *readDataDict = [NSMutableDictionary dictionaryWithCapacity:2];
    ssize_t readDataLength = read(fd,readBuff,len);
//    NSLog(@"readData length:%zd\n",readDataLength);
    if (readDataLength < 1) {
//        NSLog(@"readData failed\n");
        return (NSMutableDictionary *)readDataDict;
    } else {
        NSLog(@"readData Result:>>\nlength:%zd\nread data:\n==========*****==========\n%s\n==========*****==========",readDataLength,readBuff);
        NSString *readStr =[NSString stringWithFormat:@"%s",readBuff];
        readDataDict[@"readDataLength"]=[NSNumber numberWithInt:(int)readDataLength];
        readDataDict[@"readData"] = readStr;
        return (NSMutableDictionary *)readDataDict;
    }
}


/*
* Print read data char from serial device
*
* @param readData Read data of serial device.
*
* @param length Read data length.
*
*/
- (void)printReadBuff :(char *)readData :(ssize_t)length {
    for (int i = 0; i < length; i++) {
        printf("%c\n", readData[i]);
    }
}


/*
* Close serial device
*
* @param fd The number of serial device.
*
* @return isClose The close status number of close serial device.
*/
- (int)serialCloseDevice:(int)fd {
    int isClose = close(fd);
    if (isClose == 0) {
        NSLog(@"close divice fd:%d success\n",fd);
    }else {
        NSLog(@"close divice fd:%d failed\n",fd);
    }
    return isClose;
}

@end
